package com.bolt.core.view.templates;

import com.bolt.common.BoltConstants;
import com.bolt.common.io.FastByteArrayOutputStream;
import com.bolt.common.io.IoUtil;
import com.bolt.convention.exception.ServiceException;
import com.bolt.core.view.components.ComponentsBase;
import freemarker.ext.servlet.*;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapperBuilder;
import freemarker.template.ObjectWrapper;
import freemarker.template.SimpleHash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;


public class FreemarkerTemplateEngine {

    private  Logger logger = LoggerFactory.getLogger(FreemarkerTemplateEngine.class);

    private static final String FILE_SUFFIX = "ftl";


    private Configuration configuration;


    public FreemarkerTemplateEngine(Configuration configuration) {
        this.configuration = configuration;
    }

    public Configuration getConfiguration(){
        return configuration;
    }

    public SimpleHash buildTemplateModel(HttpServletRequest request, HttpServletResponse response) {

        AllHttpScopesHashModel fmModel = new AllHttpScopesHashModel(getObjectWrapper(),request.getServletContext(), request);
        fmModel.put(FreemarkerServlet.KEY_APPLICATION, new ServletContextHashModel(request.getServletContext(), getObjectWrapper()));
        fmModel.put(FreemarkerServlet.KEY_REQUEST, new HttpRequestHashModel(request, response, getObjectWrapper()));
        fmModel.put(FreemarkerServlet.KEY_REQUEST_PARAMETERS, new HttpRequestParametersHashModel(request));
        fmModel.put(FreemarkerServlet.KEY_SESSION, buildSessionModel(request,response));
        return fmModel;
    }


    private  HttpSessionHashModel buildSessionModel(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            return new HttpSessionHashModel(session, getObjectWrapper());
        } else {
            return new HttpSessionHashModel(null, request, response, getObjectWrapper());
        }
    }


    private ObjectWrapper getObjectWrapper() {
        ObjectWrapper ow = getConfiguration().getObjectWrapper();
        return (ow != null ? ow : new DefaultObjectWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build());
    }


    protected String getFinalTemplateName(Template template) {
        String t = template.toString();
        if (t.indexOf(".") <= 0) {
            return t + "." + FILE_SUFFIX;
        }
        return t;
    }

    public void renderString(String context,Writer writer ){
        try{
            FastByteArrayOutputStream  outputStream = IoUtil.read(new ByteArrayInputStream(context.getBytes()));
            outputStream.writeTo(writer,"UTF-8");
        }catch(Exception ex){
            throw new ServiceException(ex);
        }
    }

    /**
     * 返回静态HTML代码
     * @param path
     * @param tag
     * @return
     */
    public String toHtml(String path, ComponentsBase tag,HttpServletRequest request, HttpServletResponse response){
        StringWriter output = new StringWriter();
        try {

            freemarker.template.Template template = configuration.getTemplate(path,"utf-8");
            SimpleHash fmModel = buildTemplateModel(request,response);
            fmModel.put("tag", tag);
            if(tag.getParameters().containsKey(BoltConstants.FORM_ITME_VALUE_ATTRIBUTE)){
                fmModel.put(BoltConstants.FORM_ITME_VALUE_ATTRIBUTE,tag.getParameters().get(BoltConstants.FORM_ITME_VALUE_ATTRIBUTE));
            }
            template.process(fmModel, output);
            return output.toString();
        } catch (Exception ex) {
            throw new ServiceException(ex);
        } finally {
            try{
                output.close();
            }catch (IOException ex){
                throw new ServiceException(ex);
            }
        }
    }

    public void renderTemplate(TemplateRenderingContext templateContext) {

        String templateName = getFinalTemplateName(templateContext.getTemplate());
        SimpleHash fmModel = buildTemplateModel(templateContext.getRequest(),templateContext.getResponse());
        Exception exception = null;
        freemarker.template.Template template = null;
        try {
            template = configuration.getTemplate(templateName,"utf-8");
        } catch (Exception ex) {
            exception = ex;
        }
        if (template == null) {
            if (logger.isErrorEnabled()) {
                logger.error("Could not load the FreeMarker template named ["+ templateContext.getTemplate().getName()+"]");
            }
            if (exception != null) {
                throw new ServiceException(exception);
            } else {
                return;
            }
        }
        try {
            Writer writer =  templateContext.getWriter();
            final Writer wrapped = writer;
            writer = new Writer() {
                @Override
                public void write(char[] cbuf, int off, int len) throws IOException {
                    wrapped.write(cbuf, off, len);
                }

                @Override
                public void flush() throws IOException {
                    // nothing!
                }

                @Override
                public void close() throws IOException {
                    wrapped.close();
                }
            };

            fmModel.put("tag", templateContext.getTag());
            template.process(fmModel, writer);
        } catch (Exception ex) {
            throw new ServiceException(ex);
        }

    }

}
